#include "SenetBoardDraft.h"

void SenetBoardDraft::extractBoardData(const SenetBoard& board, int boardSize, int initialPiecesNum)
{
	int whitePos = 0;
	int blackPos = 0;
	m_boardThirdSize = boardSize / 3;
	for(int i = 0 ; i < boardSize ; ++i)
	{
		//save board local copy
		SenetBoard::SquareData square = board.getBoardState(i);
		m_board[i].player_color = square.player_color;
		m_board[i].rebirth_id = square.rebirth_id;
		m_board[i].rebirth_to = square.rebirth_to;
		m_board[i].square_type = square.square_type;
		if(square.square_type == SenetBoard::SAFE)
		{
			++m_safeSquareNum;
		}
		
		//analyze board to save interesting data:
		//1. number of player's pieces
		//2. pieces location
		//3. number of player's pieces in first third of board 
		switch (square.player_color)
		{
		case Definitions::WHITE : 
			{
				++m_playerPieceNum[WHITE];
				m_piecesLoc[WHITE][whitePos] = i;
				++whitePos;
				if(i < m_boardThirdSize)
				{
					++(m_piecesOnFirstThird[WHITE]);
				}
				break;
			}
		case Definitions::BLACK:
			{
				++m_playerPieceNum[BLACK];
				m_piecesLoc[BLACK][blackPos] = i;
				++blackPos;
				if(i < m_boardThirdSize)
				{
					++(m_piecesOnFirstThird[BLACK]);
				}
				break;
			}
		default : ;
		}
	}

	//fill remaining m_piecesLoc[player] cells with -1 (default for piece out of board)
	for(int i = whitePos; i < initialPiecesNum; ++i)
	{
		m_piecesLoc[WHITE][i] = -1;
	}
	for(int i = blackPos; i < initialPiecesNum; ++i)
	{
		m_piecesLoc[BLACK][i] = -1;
	}
}

SenetBoardDraft::SenetBoardDraft(const SenetBoard& board, int boardSize, 
								 int initialPiecesNum)
								 : m_boardSize(boardSize)
{
	//init local variables
	m_piecesLoc.resize(2);
	m_piecesLoc[WHITE].resize(initialPiecesNum);
	m_piecesLoc[BLACK].resize(initialPiecesNum);
	m_piecesOnFirstThird[WHITE] = 0;
	m_piecesOnFirstThird[BLACK] = 0;
	m_playerPieceNum[WHITE] = 0;
	m_playerPieceNum[BLACK] = 0;
	m_board.resize(m_boardSize);	
	m_safeSquareNum = 0;
	extractBoardData(board, boardSize, initialPiecesNum);
}



SenetBoardDraft::~SenetBoardDraft()
{
	/*if(m_piecesLoc[WHITE] != 0)
		{
			delete(m_piecesLoc[WHITE]);
		}
	if(m_piecesLoc[BLACK] != 0)
	{
		delete(m_piecesLoc[BLACK]);
	}*/
}

const SenetBoard::SquareData& SenetBoardDraft::operator [](const int a) const
{
	// TODO: might need to erase bounds check
	if(a < 0 || a >= (int)m_board.size())
	{
		throw "SenetBoardDraft.operator[] - index out of bound";
	}

	return m_board[a];
}

void SenetBoardDraft::generateMoves(vector<int>& moves, Definitions::PlayerColor currentPlayer , int stickNum) const
	{	
		PiecesLocIndex player = getPiecesLocIndexFromPlayer(currentPlayer);
		moves.reserve(m_playerPieceNum[player]); // there are at most "number of pieces" moves available												

		//iterate on all pieces
		for(int i = 0 ; i < m_playerPieceNum[player]; ++i)
		{
			if(isLegalMove(m_piecesLoc[player][i],currentPlayer, stickNum))
			{
				moves.push_back(m_piecesLoc[player][i]);
			}
		}
	}



void SenetBoardDraft::doMove(vector<SenetBoardDraftMove>& movesPerformed ,  int pieceToMove, int move_to_square ,
								Definitions::PlayerColor playerColor)
{
	if(pieceToMove == move_to_square)
	{
		//do not do any work for empty move
		movesPerformed.push_back((SenetBoardDraftMove(pieceToMove, move_to_square)));
		return;
	}
	PiecesLocIndex player = getPiecesLocIndexFromPlayer(playerColor);

	int res;
	if(move_to_square >= m_boardSize) 
	{
		//remove piece from board
		removePieceFromBoard(pieceToMove , player);	
		movesPerformed.push_back((SenetBoardDraftMove(pieceToMove , m_boardSize + 1)));
	}
	else 
	{
		//TODO: Debug checkBoardCoherancy();
		
		//move inside the board (both regular move and undo move will use this)
		movePiece(movesPerformed , pieceToMove, move_to_square, player , playerColor);
		
		/*checkBoardCoherancy();
		int x;
		x=1;*/
	}	
}

void SenetBoardDraft::undoMove(int pieceToMove , int move_to_square , Definitions::PlayerColor playerColor)
{
	if(pieceToMove == move_to_square)
	{
		//do not do any work for empty move
		return;
	}
	PiecesLocIndex player = getPiecesLocIndexFromPlayer(playerColor);
	if(pieceToMove >= m_boardSize)
	{
		//undo move - return piece that was removed
		if(move_to_square >= m_boardSize)
		{
			throw "SenetBoardDraft.doMove - illegal move request, both orig and dest locations are out of board";
		}
		returnPieceToBard(move_to_square , player, playerColor);
		
	}
	else
	{
		//move is inside the board - simply switch

		if(m_board[move_to_square].player_color == getOppositeColor(playerColor))
		{
			//eat will be performed - update location of opposite player eaten piece
			updateLocation(getOpositeLocIndex(player), move_to_square , pieceToMove);
		}
		
		//do move:
		std::swap(m_board[pieceToMove].player_color, m_board[move_to_square].player_color);

		//update location:
		updateLocation(player , pieceToMove , move_to_square);
	}
}